﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Model
{
    // 基本实体类
    public class Entity : ComponentSuperior
    {
        // 实体已经作为了一个特殊组件，GID即为ComponentSuperior的InstID

        // 当前实体挂载的组件表
        private Dictionary<Type, Component> componentDict;

        public Entity()
        {
            this.componentDict = new Dictionary<Type, Component>();
        }
        protected Entity(long id) : base(id)
        {
            this.componentDict = new Dictionary<Type, Component>();
        }
        /// <summary>
        /// 添加指定组件
        /// </summary>
        /// <typeparam name="T">组件类型[Component]</typeparam>
        /// <returns>添加的组件</returns>
        public T AddComponent<T>()
            where T : Component, new()
        {
            //获取T的类型
            Type type = typeof(T);
            //一个实体不能同时存在多个相同组件【冲突】
            if (this.componentDict.ContainsKey(type))
            {
                throw new Exception($"AddComponent时出现错误：已存在相同组件。相关实体ID：{this.InstId},组件名: {typeof(T).Name}");
            }
            //初始化组件[同时设置该组件目标实体为该实体]
            T component = ComponentFactory.CreateWithParent<T>(this);
            //提交自身
            GameRoot.DispatcherSystem.AddComponent(component);
            //字典添加该组件
            componentDict.Add(type, component);
            //主事件系统添加该事件【在有关该组件的事件发生时关联】
            //GameRoot.EventSystem.Add(component);
            return component;
        }
        /// <summary>
        /// 添加指定组件[带参数]
        /// </summary>
        /// <typeparam name="T">组件类型[Component]</typeparam>
        /// <typeparam name="A">参数类型A</typeparam>
        /// <param name="a">参数a</param>
        /// <returns></returns>
        public T AddComponent<T, A>(A a)
            where T:Component,new()
        {
            Type type = typeof(T);
            if (this.componentDict.ContainsKey(type))
            {
                throw new Exception($"AddComponent时出现错误：已存在相同组件。相关实体ID：{this.InstId},组件名: {typeof(T).Name}");
            }
            T component = ComponentFactory.CreateWithParent<T, A>(this, a);
            //提交自身
            GameRoot.DispatcherSystem.AddComponent(component);
            this.componentDict.Add(type, component);
            return component;
        }
        /// <summary>
        /// 获取指定组件
        /// </summary>
        /// <typeparam name="T">组件类型</typeparam>
        /// <returns>获取的组件</returns>
        public T GetComponent<T>()
            where T : Component
        {
            Component component;
            if (!this.componentDict.TryGetValue(typeof(T), out component))
            {
                return default(T);
            }
            return (T)component;
        }
        /// <summary>
        /// 获取指定组件
        /// </summary>
        /// <param name="type">类型名</param>
        /// <returns>获取的组件</returns>
        public Component GetComponent(Type type)
        {
            Component component;
            if (!this.componentDict.TryGetValue(type, out component))
            {
                return null;
            }
            return component;
        }
        /// <summary>
        /// 获取当前实体的所有组件
        /// </summary>
        /// <returns></returns>
        public Component[] GetComponents()
        {
            return this.componentDict.Values.ToArray();
        }
        /// <summary>
        /// 移除指定类型组件
        /// </summary>
        /// <typeparam name="T">组件类型</typeparam>
        public void RemoveComponent<T>()
        {
            //如果当前实体已经销毁不做处理
            if (this.IsDisposed)
                return;
            Type type = typeof(T);
            Component component;
            if (!this.componentDict.TryGetValue(type, out component))
                return;
            this.componentDict.Remove(type);
            GameRoot.DispatcherSystem.RemoveComponent(component.InstId);
            component.Dispose();
        }
        /// <summary>
        /// 移除指定类型组件
        /// </summary>
        /// <param name="type">类型名</param>
        public void RemoveComponent(Type type)
        {
            if (this.IsDisposed)
                return;
            Component component;
            if (!this.componentDict.TryGetValue(type, out component))
            {
                return;
            }
            this.componentDict.Remove(type);
            GameRoot.DispatcherSystem.RemoveComponent(component.InstId);
            component.Dispose();
        }
        /// <summary>
        /// 销毁当前实体
        /// </summary>
        public override void Dispose()
        {
            if (this.IsDisposed)
                return;
            base.Dispose();
            //依次销毁该实体上挂载的所有组件
            foreach (Component c in this.componentDict.Values)
            {
                try
                {
                    GameRoot.DispatcherSystem.RemoveComponent(c.InstId);
                    c.Dispose();
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
            }
            this.componentDict.Clear();
            this.InstID = 0;
        }
        /// <summary>
        /// 批初始化结束
        /// </summary>
        public override void EndInit()
        {
            try
            {
                base.EndInit();
                this.componentDict.Clear();

            }catch(Exception e)
            {
                Log.Error(e);
            }
        }
    }
}
